Skip to content

fix(ui): give every page a main landmark and mark the sidebars as navigation - #1587

Open
culfin wants to merge 2 commits into
apache:devfrom
Besser-Sehen-Landshut:fix/landmarks-main-and-nav
Open

fix(ui): give every page a main landmark and mark the sidebars as navigation#1587
culfin wants to merge 2 commits into
apache:devfrom
Besser-Sehen-Landshut:fix/landmarks-main-and-nav

Conversation

@culfin

@culfin culfin commented Aug 24, 2026

Copy link
Copy Markdown

No page of the interface carries a main landmark, and the sidebars are plain
divs.

Visible on this project's own instance

meta.answer.dev/questions, fetched with a Googlebot user agent:

$ curl -s -A "…Googlebot…" https://meta.answer.dev/questions | grep -c "<main"
0

Same in the source:

$ grep -rn "<main\|role=\"main\"" ui/src ui/template | wc -l
0

Why it matters

Screen reader users navigate by landmarks. Without a main, there is no way to
skip past the header and the sidebar to the content — every visit to every page
starts by tabbing through the whole navigation again. That is WCAG 2.4.1
(Bypass Blocks), and a landmark is the least intrusive way to satisfy it.

The change

Every route now sits inside exactly one main:

layout covers
SideNavLayout, SideNavLayoutWithoutFooter the forum, tags, users, badges
Admin 28 admin routes
new PlainLayout (pathless) 19 routes with no layout of their own — signing in, registering, account recovery, the error pages

pages/Layout would have been the wrong place for a single landmark: it wraps
the header, so main there would put the navigation inside the content region
and "skip to content" would land before it.

The sidebar containers become nav in the same three files. Class names are
untouched, so nothing moves on screen.

Verified

  • Structurally: 88 paths before, the same 88 after, no page removed, three
    layout nodes added.
  • By running it: built the front end and stepped through /users/login,
    /users/register, /50x and an unknown path — each renders inside exactly
    one main and draws its content.
  • prettier, eslint, tsc.

The router diff looks larger than it is. Read with git diff -w it is 24
added lines; everything else is one indentation level.

Deliberately not included

With two nav landmarks on a page — this one and the header — an aria-label
on each would tell them apart. That needs a new i18n key across 45 language
files, which does not belong in a change that is otherwise markup only.

Supersedes #1589 and #1591, which were the same work split across three pull
requests.

🤖 Generated with Claude Code

No page of the interface carries a `main` landmark — `grep` for `<main` or
`role="main"` across `ui/src` and `ui/template` returns nothing. The sidebar
is a plain `div` as well.

Screen reader users navigate by landmarks. Without a `main`, there is no way
to skip past the header and the sidebar to the content; every visit to every
page starts by tabbing through the whole navigation again. WCAG 2.4.1
(Bypass Blocks) is the criterion, and a landmark is the least intrusive way
to satisfy it.

Both layouts that carry the sidebar are changed: the wrapper around `Outlet`
becomes `main`, and the sidebar container becomes `nav`. Class names are
untouched, so nothing moves.

Not included, and worth a look separately: the layouts that do not use the
sidebar (`Admin`, `Users/Settings`, `Legal`) still need one, and with two
`nav` landmarks on a page — this one and the header — an `aria-label` on each
would help. That needs a new i18n key, so it is left out of a change that is
otherwise markup only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The admin area has a layout of its own and sits directly under `pages/Layout`,
so the two changes above did not reach it. Nineteen further routes — signing
in, registering, recovering an account, the error pages — have no layout at
all; they get a pathless one that is nothing but a `main`.

`pages/Layout` itself would be the wrong place: it wraps the header, so a
landmark there would put the navigation inside the content region and "skip to
content" would land before it.

Verified structurally — 88 paths before, the same 88 after, no page removed —
and by building the front end and stepping through the affected routes: each
renders inside exactly one `main` and draws its content.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@culfin
culfin changed the base branch from main to dev August 24, 2026 18:00
@culfin culfin changed the title fix(ui): give pages a main landmark and mark the sidebar as navigation fix(ui): give every page a main landmark and mark the sidebars as navigation Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant